Working with the FileInfo Class

As shown in the previous DirectoryApp example, the FileInfo class allows you to obtain details regarding existing files on your hard drive (e.g., time created, size, and file attributes) and aids in the creation, copying, moving, and destruction of files. In addition to the set of functionality inherited by FileSystemInfo, you can find some core members unique to the FileInfo class, which you can see described in Table 20-4.

Table 20-4. FileInfo Core Members

Member Meaning in Life
AppendText() Creates a StreamWriter object (described later) that appends text to a file.
CopyTo() Copies an existing file to a new file.
Create() Creates a new file and returns a FileStream object (described later) to interact with the newly created file.
CreateText() Creates a StreamWriter object that writes a new text file.
Delete() Deletes the file to which a FileInfo instance is bound.
Directory Gets an instance of the parent directory.
DirectoryName Gets the full path to the parent directory.
Length Gets the size of the current file.
MoveTo() Moves a specified file to a new location, providing the option to specify a new file name.
Name Gets the name of the file.
Open() Opens a file with various read/write and sharing privileges.
OpenRead() Creates a read-only FileStream object.
OpenText() Creates a StreamReader object (described later) that reads from an existing text file.
OpenWrite() Creates a write-only FileStream object.

Note that a majority of the methods of the FileInfo class return a specific I/O-centric object (e.g., FileStream and StreamWriter) that allows you to begin reading and writing data to (or reading from) the associated file in a variety of formats. You will check out these types in just a moment; however, before you see a working example, you’ll find it helpful to examine various ways to obtain a file handle using the FileInfo class type.

The FileInfo.Create() Method

One way you can create a file handle is to use the FileInfo.Create() method:

static void Main(string[] args)
{
    // Make a new file on the C drive.
    FileInfo f = new FileInfo(@"C:\Test.dat");
    FileStream fs = f.Create();

    // Use the FileStream object...

    // Close down file stream.
    fs.Close();
}

Notice that the FileInfo.Create() method returns a FileStream object, which exposes synchronous and asynchronous write/read operations to/from the underlying file (more details in a moment). Be aware that the FileStream object returned by FileInfo.Create() grants full read/write access to all users.

Also notice that after you finish with the current FileStream object, you must ensure you close down the handle to release the underlying unmanaged stream resources. Given that FileStream implements IDisposable, you can use the C# using scope to allow the compiler to generate the teardown logic (see Chapter 8 for details):

static void Main(string[] args)
{
    // Defining a 'using scope' for file I/O
    // types is ideal.

    FileInfo f = new FileInfo(@"C:\Test.dat");
    using (FileStream fs = f.Create())
    {
        // Use the FileStream object...
    }
}

The FileInfo.Open() Method

You can use the FileInfo.Open() method to open existing files, as well as to create new files with far more precision than you can with FileInfo.Create(). This works because Open() typically takes several parameters to qualify exactly how to iterate the file you want to manipulate. Once the call to Open() completes, you are returned a FileStream object. Consider the following logic:

static void Main(string[] args)
{
    // Make a new file via FileInfo.Open().
    FileInfo f2 = new FileInfo(@"C:\Test2.dat");
    using(FileStream fs2 = f2.Open(FileMode.OpenOrCreate,
        FileAccess.ReadWrite, FileShare.None))
    {
        // Use the FileStream object...
    }
}

This version of the overloaded Open() method requires three parameters. The first parameter of the Open() method specifies the general flavor of the I/O request (e.g., make a new file, open an existing file, and append to a file), which you specify using the FileMode enumeration (see Table 20-5 for details):

public enum FileMode
{
    CreateNew,
    Create,
    Open,
    OpenOrCreate,
    Truncate,
    Append
}

Table 20-5. Members of the FileMode Enumeration

Member Meaning in Life
CreateNew Informs the OS to make a new file. If it already exists, an IOException is thrown.
Create Informs the OS to make a new file. If it already exists, it will be overwritten.
Open Opens an existing file. If the file does not exist, a FileNotFoundException is thrown.
OpenOrCreate Opens the file if it exists; otherwise, a new file is created.
Truncate Opens an existing file and truncates the file to 0 bytes in size.
Append Opens a file, moves to the end of the file, and begins write operations (you can only use this flag with a write-only stream). If the file does not exist, a new file is created.

You use the second parameter of the Open() method, a value from the FileAccess enumeration, to determine the read/write behavior of the underlying stream:

public enum FileAccess
{
    Read,
    Write,
    ReadWrite
}

Finally, the third parameter of the Open() method, FileShare, specifies how to share the file among other file handlers. Here are the core names:

public enum FileShare
{
    Delete,
    Inheritable,
    None,
    Read,
    ReadWrite,
    Write
}

The FileInfo.OpenRead() and FileInfo.OpenWrite() Methods

The FileInfo.Open() method allows you to obtain a file handle in a flexible manner, but the FileInfo class also provides members named OpenRead() and OpenWrite(). As you might imagine, these methods return a properly configured read-only or write-only FileStream object, without the need to supply various enumeration values. Like FileInfo.Create() and FileInfo.Open(), OpenRead() and OpenWrite() return a FileStream object (note that the following code assumes you have files named Test3.dat and Test4.dat on your C drive):

static void Main(string[] args)
{
    // Get a FileStream object with read-only permissions.
    FileInfo f3 = new FileInfo(@"C:\Test3.dat");
    using(FileStream readOnlyStream = f3.OpenRead())
    {
        // Use the FileStream object...
    }

    // Now get a FileStream object with write-only permissions.
    FileInfo f4 = new FileInfo(@"C:\Test4.dat");
    using(FileStream writeOnlyStream = f4.OpenWrite())
    {
        // Use the FileStream object...
    }
}

The FileInfo.OpenText() Method

Another open-centric member of the FileInfo type is OpenText(). Unlike Create(), Open(), OpenRead(), or OpenWrite(), the OpenText() method returns an instance of the StreamReader type, rather than a FileStream type. Assuming you have a file named boot.ini on your C drive, the following snippet lets you access to its contents:

static void Main(string[] args)
{
    // Get a StreamReader object.
    FileInfo f5 = new FileInfo(@"C:\boot.ini");
    using(StreamReader sreader = f5.OpenText())
    {
        // Use the StreamReader object...
    }
}

As you will see shortly, the StreamReader type provides a way to read character data from the underlying file.

The FileInfo.CreateText() and FileInfo.AppendText() Methods

The final two FileInfo methods of interest at this point are CreateText() and AppendText(). Both return a StreamWriter object, as shown here:

static void Main(string[] args)
{
    FileInfo f6 = new FileInfo(@"C:\Test6.txt");
    using(StreamWriter swriter = f6.CreateText())
    {
        // Use the StreamWriter object...
    }

    FileInfo f7 = new FileInfo(@"C:\FinalTest.txt");
    using(StreamWriter swriterAppend = f7.AppendText())
    {
        // Use the StreamWriter object...
    }    
}

As you might guess, the StreamWriter type provides a way to write character data to the underlying file.